package com.jiwei.community.entity;

import com.alibaba.fastjson.annotation.JSONField;
import com.jiwei.community.entity.SecurityCacheUser;
import com.jiwei.community.entity.User;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.logging.log4j.util.Strings;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Author 季伟
 * 功能：该类用来封装用户认证时从数据库中查询出来的用户信息来供spring security的 各个过滤器使用
 */
@Data
@NoArgsConstructor
public class LoginUser implements UserDetails {
    /**
     * 用户重要的信息
     * 会保存到缓存中等更新时只需要直接将所有信息从缓存中删除
     */
    private SecurityCacheUser cacheUser;
    private List<String> permissions;
    private List<String> roles;
    private String token;
    /**
     * 加上@JSONField(serialize = false)
     * 使这个类进行序列化的时候不参与序列化否则fastJson会报AutoType is not support的错误，
     * 因为fastJson在进行反序列化的时候要根据AutoType确定一个类中的抽象类或者接口的变量的实际实现类型，
     * 同时AutoType中有白名单机制必须在这个白名单中才能进行反序列化，
     * 而spring库中的类默认都不在这个白名单中，
     * 因此如果不将SimpleGrantedAuthority配置到白名单中就会报错，
     * 可以通过ParserConfig.getGlobalInstance().addAccept("org.springframework.security.core.authority.")
     * 将springSecurity核心库中的类配置到白名单中使之能偶反序列化。
     * 但在较低版本的fastJson中进行反序列化时还需要保证该类中拥有无参构造器，而SimpleGrantedAuthority没有无参构造器所以最后选择不将该属性参与序列化
     */
    @JSONField(serialize = false)
    private List<GrantedAuthority> authorities;
    /**
     * 完整的用户信息只有在用户登录时才会保证有值然后将用户头像等信息返回给客户端
     * 但不会保存到缓存中
     */
    @JSONField(serialize = false)
    private User user;


    public LoginUser(SecurityCacheUser cacheUser, List<String> permissions, List<String> roles, User user) {
        this.cacheUser = cacheUser;
        this.permissions = permissions;
        this.user = user;
        this.roles = roles;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        if (Objects.isNull(authorities)){
            if (Objects.isNull(permissions)){
                return new ArrayList<>();
            }
            authorities = permissions.stream()
                    .filter(Strings::isNotEmpty)
                    .map(SimpleGrantedAuthority::new)
                    .collect(Collectors.toList());
        }
        return authorities;
    }

    @Override
    public String getPassword() {
        return cacheUser.getPassword();
    }

    @Override
    public String getUsername() {
        return cacheUser.getUserName();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    public SecurityCacheUser getCacheUser(){
        return cacheUser;
    }

    public User getUser(){
        return user;
    }
}
